package com.zjj.lbw.designpattern.singleton;

/**
 * @author zhanglei.zjj
 * @description DCL实现 懒汉单例模式
 * 要解决问题：
 * 1. 多线程有并发问题，需要加锁，如果直接对整个方法加锁粒度太大，只能对对象实例化关键代码加锁
 * 2. 需要使用双重检查锁，避免被实例化多次
 * 3. 构造方法实例化过程可能发发生指令重排，对象实例属性需要加volatile关键字
 * @date 2023/7/11 15:24
 */
public class LazySingletonTest {
}

class LazySingleton {
    private volatile static LazySingleton instance;

    /**
     * 构造方法私有化
     */
    private LazySingleton() {
        synchronized (LazySingleton.class) {
            if (LazySingleton.instance != null) {
                throw new RuntimeException(" 不允许多个实例。");
            }

            // 执行到这里可能时间片用完了，可能发生异常释放锁
            instance = this;
        }
    }

    /**
     * 提供单例对外访问入口
     * @return
     */
    public LazySingleton getInstance() {
        if (instance == null) {
            synchronized (LazySingleton.class) {
                if (instance == null) {
                    /*
                    字节码层，JIT，CPU 有可能对如下指令进行重排序
                    大致过程：
                    1. 分配空间
                    2. 初始化
                    3. 引用赋值
                    可能重排为：1 -> 3 -> 2
                    如果在完成第3步，有其他线程来获取实例，将拿到尚未初始化好的实例

                     */
                    instance = new LazySingleton();
                }
            }
        }
        return instance;
    }
}